variant.hpp
namespace type_safe
{
template <typename T>
using variant_type = union_type<T>;
template <typename ... Ts>
using variant_types = union_types<Ts...>;
struct nullvar_t;
constexpr nullvar_t nullvar;
template <class VariantPolicy, typename HeadT, typename ... TailT>
class basic_variant;
template <class VariantPolicy, typename Head, typename ... Types>
bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator==(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator!=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator<(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator<=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator>(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator>=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator==(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator!=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator<(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator<=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator>(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator>=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types>
bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
void with(basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);
template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
void with(const basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);
template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
void with(basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);
template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
void with(const basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);
template <typename Fallback>
class fallback_variant_policy;
template <typename Fallback, typename ... OtherTypes>
using fallback_variant = basic_variant<fallback_variant_policy<Fallback>, Fallback, OtherTypes...>;
class optional_variant_policy;
using rarely_empty_variant_policy = 'hidden';
using never_empty_variant_policy = 'hidden';
template <typename ... Types>
using variant = typename detail::select_variant_policy<Types...>::type;
}
type_safe::variant_type
[variant]template <typename T>
using variant_type = union_type<T>;
Convenience alias for ts::union_type.
type_safe::variant_types
[variant]template <typename ... Ts>
using variant_types = union_types<Ts...>;
Convenience alias for ts::union_types.
type_safe::nullvar_t
[variant]struct nullvar_t
{
constexpr nullvar_t();
};
Tag type to mark a ts::basic_variant without a value.
type_safe::nullvar
[variant]constexpr nullvar_t nullvar;
Tag object of type ts::nullvar_t.
type_safe::basic_variant
[variant]template <class VariantPolicy, typename HeadT, typename ... TailT>
class basic_variant
{
public:
using types = typename union_t::types;
using type_id = typename union_t::type_id;
using allow_empty = typename VariantPolicy::allow_empty;
static constexpr type_id invalid_type = union_t::;
basic_variant() noexcept;
basic_variant(nullvar_t) noexcept;
basic_variant(const basic_variant&) = default;
basic_variant(basic_variant&&) = default;
template <typename T, typename ... Args>
basic_variant(variant_type<T> type, Args&&... args);
template <typename T, typename = detail::enable_variant_type<union_t, T, T&&>>
basic_variant(T&& obj);
basic_variant(const tagged_union<HeadT, TailT...>& u);
basic_variant(tagged_union<HeadT, TailT...>&& u);
~basic_variant() noexcept = default;
basic_variant& operator=(const basic_variant&) = default;
basic_variant& operator=(basic_variant&&) = default;
basic_variant& operator=(nullvar_t) noexcept;
template <typename T>
basic_variant& operator=(T&& obj);
friend void swap(basic_variant& a, basic_variant& b) noexcept('hidden');
void reset() noexcept;
template <typename T, typename Arg>
void emplace(variant_type<T> type, Arg&& arg);
template <typename T, typename ... Args>
void emplace(variant_type<T> type, Args&&... args);
type_id type() const noexcept;
bool has_value() const noexcept;
operator bool() const noexcept;
bool has_value(variant_type<nullvar_t>) const noexcept;
template <typename T>
bool has_value(variant_type<T> type) const noexcept;
nullvar_t value(variant_type<nullvar_t>) const noexcept;
template <typename T, typename = enable_valid<T>>
T& value(variant_type<T> type) & noexcept;
template <typename T>
const T& value(variant_type<T> type) const & noexcept;
template <typename T>
T&& value(variant_type<T> type) && noexcept;
template <typename T>
const T&& value(variant_type<T> type) const && noexcept;
optional_ref<const nullvar_t> optional_value(variant_type<nullvar_t>) const noexcept;
template <typename T>
optional_ref<T> optional_value(variant_type<T> type) & noexcept;
template <typename T>
optional_ref<const T> optional_value(variant_type<T> type) const & noexcept;
template <typename T>
optional_xvalue_ref<T> optional_value(variant_type<T> type) && noexcept;
template <typename T>
optional_xvalue_ref<const T> optional_value(variant_type<T> type) const && noexcept;
template <typename T, typename U>
T value_or(variant_type<T> type, U&& other) const &;
template <typename T, typename U>
T value_or(variant_type<T> type, U&& other) &&;
template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::copy_constructible::value, Dummy>::type>
basic_variant map(Functor&& f, Args&&... args) const &;
template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::move_constructible::value, Dummy>::type>
basic_variant map(Functor&& f, Args&&... args) &&;
};
An improved union
storing at most one of the given types at a time (or possibly none).
It is an improved version of std::variant. A big problem with variant is implementing the operation that changes the type. It has to destroy the old value and then create the new one. But how to handle an exception when creating the new type? There are multiple ways of handling this, so it is outsourced in a policy. The variant policy is a class that must have the following members:
allow_empty
- either std::true_type or std::false_type. If it is "true", the variant can be put in the empty state explicitly.void change_value(variant_type<T>, tagged_union<Types...>&, Args&&... args)
- changes the value and type. It will be called when the variant already contains an object of a different type. It must destroy the old type and create a new one with the given type and arguments.void change_value(variant_type<T>, tagged_union<Types...>&, Args&&... args)
- changes the value and type. It will be called when the variant already contains an object of a different type. It must destroy the old type and create a new one with the given type and arguments.type_safe::basic_variant::basic_variant::basic_variant
(1) basic_variant() noexcept;
(2) basic_variant(nullvar_t) noexcept;
Effects: Initializes the variant to the empty state.
Notes: This constructor only participates in overload resolution, if the policy allows an empty variant.
type_safe::basic_variant::basic_variant
(1) basic_variant(const basic_variant&) = default;
(2) basic_variant(basic_variant&&) = default;
Copy (1)/move (2) constructs a variant.
Effects: If the other variant is not empty, it will call ts::copy (1) or ts::move (2). \throws Anything thrown by the copy (1)/move (2) constructor. \notes This constructor only participates in overload resolution, if all types are copy (1)/move (2) constructible.
Notes: The move constructor only moves the stored value, and does not make the other variant empty.
type_safe::basic_variant::basic_variant
template <typename T, typename ... Args>
basic_variant(variant_type<T> type, Args&&... args);
Initializes it containing a new object of the given type.
Effects: Creates it by calling T
s constructor with the perfectly forwarded arguments.
Throws: Anything thrown by T
s constructor.
Notes: This constructor does not participate in overload resolution, unless T
is a valid type for the variant and constructible from the arguments.
type_safe::basic_variant::basic_variant
template <typename T, typename = detail::enable_variant_type<union_t, T, T&&>>
basic_variant(T&& obj);
Initializes it with a copy of the given object.
Effects: Same as the type + argument constructor called with the decayed type of the argument and the object perfectly forwarded. \throws Anything thrown by T
s copy/move constructor. \notes This constructor does not participate in overload resolution, unless T
is a valid type for the variant and copy/move constructible. \param 1 \exclude
type_safe::basic_variant::basic_variant
(1) basic_variant(const tagged_union<HeadT, TailT...>& u);
(2) basic_variant(tagged_union<HeadT, TailT...>&& u);
Initializes it from a ts::tagged_union.
Effects: Copies the currently stored type of the union into the variant by calling the copy (1)/move (2) constructor of the stored type.
Throws: Anything thrown by the selected copy (1)/move (2) constructor.
Requires: If the variant policy does not allow the empty state, the union must not be empty.
type_safe::basic_variant::~basic_variant
~basic_variant() noexcept = default;
Effects: Destroys the currently stored value, if there is any.
type_safe::basic_variant::operator=
basic_variant& operator=(const basic_variant&) = default;
Copy (1)/move (2) assigns a variant.
Effects: If the other variant is empty, makes this one empty as well. Otherwise let the other variant contains an object of type T
. If this variant contains the same type and there is a copy (1)/move (2) assignment operator available, assigns the object to this object. Else forwards to the variant policy's change_value()
function. \throws Anything thrown by either the copy (1)/move (2) assignment operator or copy (1)/move (2) constructor. If the assignment operator throws, the variant will contain the partially assigned object. If the constructor throws, the state depends on the variant policy. \notes This function does not participate in overload resolution, unless all types are copy (1)/move (2) constructible. \group copy_move_assign
type_safe::basic_variant::operator=
(1) basic_variant& operator=(basic_variant&&) = default;
type_safe::basic_variant::operator=::operator=
basic_variant& operator=(nullvar_t) noexcept;
Alias for reset().
type_safe::basic_variant::operator=
template <typename T>
basic_variant& operator=(T&& obj);
Same as the single argument emplace()
.
Effects: Changes the value to a copy of obj
.
Throws: Anything thrown by T
s copy/move constructor.
Notes: This function does not participate in overload resolution, unless T
is a valid type for the variant and copy/move constructible.
type_safe::swap
friend void swap(basic_variant& a, basic_variant& b) noexcept('hidden');
Swaps two variants.
Effects: There are four cases:
T
. Then it calls swap on the stored type.Effects: In either case, it will only call the swap() function or the move constructor.
Throws: Anything thrown by the swap function, in which case both variants contain the partially swapped values, or the mvoe constructor, in which case the exact behavior depends on the variant policy.
type_safe::basic_variant::reset::reset
void reset() noexcept;
Effects: Destroys the stored value in the variant, if any.
Notes: This function only participate in overload resolution, if the variant policy allows the empty state.
type_safe::basic_variant::emplace
template <typename T, typename Arg>
void emplace(variant_type<T> type, Arg&& arg);
Changes the value to a new object of the given type.
Effects: If the variant contains an object of the same type, assigns the argument to it. Otherwise behaves as the other emplace version.
Throws: Anything thrown by the chosen assignment operator or the other emplace()
. If the assignment operator throws, the variant contains a partially assigned object. Otherwise it depends on the variant policy.
Notes: This function does not participate in overload resolution, unless T
is a valid type for the variant and assignable from the argument without creating an additional temporary.
type_safe::basic_variant::emplace
template <typename T, typename ... Args>
void emplace(variant_type<T> type, Args&&... args);
Changes the value to a new object of given type.
Effects: If variant is empty, creates the object directly in place by perfectly forwarding the arguments. Otherwise it forwards to the variant policy's change_value()
function.
Throws: Anything thrown by T
s constructor or possibly move constructor. If the variant was empty before, it is still empty afterwards. Otherwise the state depends on the policy.
Notes: This function does not participate in overload resolution, unless T
is a valid type for the variant and constructible from the arguments.
type_safe::basic_variant::type
type_id type() const noexcept;
Returns: The type id representing the type of the value currently stored in the variant.
Notes: If it does not have a value stored, returns invalid_type.
type_safe::basic_variant::has_value
(1) bool has_value() const noexcept;
(2) operator bool() const noexcept;
(3) bool has_value(variant_type<nullvar_t>) const noexcept;
Returns: true
if the variant currently contains a value, false
otherwise.
Notes: Depending on the variant policy, it can be guaranteed to return true
all the time.
type_safe::basic_variant::has_value
template <typename T>
bool has_value(variant_type<T> type) const noexcept;
Returns: true
if the variant currently stores an object of type T
, false
otherwise.
Notes: T
must not necessarily be a type that can be stored in the variant.
type_safe::basic_variant::value
nullvar_t value(variant_type<nullvar_t>) const noexcept;
Returns: A copy of ts::nullvar.
Requires: The variant must be empty.
type_safe::basic_variant::value
template <typename T, typename = enable_valid<T>>
T& value(variant_type<T> type) & noexcept;
Returns: A (const
) lvalue (1, 2)/rvalue (3, 4) reference to the stored object of the given type. \requires The variant must currently store an object of the given type, i.e. has_value(type)
must return true
. \group value \param 1 \exclude
type_safe::basic_variant::value
(1) template <typename T>
const T& value(variant_type<T> type) const & noexcept;
(2) template <typename T>
T&& value(variant_type<T> type) && noexcept;
(3) template <typename T>
const T&& value(variant_type<T> type) const && noexcept;
type_safe::basic_variant::optional_value
optional_ref<const nullvar_t> optional_value(variant_type<nullvar_t>) const noexcept;
Returns: A ts::optional_ref to ts::nullvar. If the variant is not empty, returns a null reference.
type_safe::basic_variant::optional_value
template <typename T>
optional_ref<T> optional_value(variant_type<T> type) & noexcept;
Returns: A (const
) ts::optional_ref (1, 2)/ts::optional_xvalue_ref to the stored value of given type. If it stores a different type, returns a null reference. \group optional_value
type_safe::basic_variant::optional_value
(1) template <typename T>
optional_ref<const T> optional_value(variant_type<T> type) const & noexcept;
(2) template <typename T>
optional_xvalue_ref<T> optional_value(variant_type<T> type) && noexcept;
(3) template <typename T>
optional_xvalue_ref<const T> optional_value(variant_type<T> type) const && noexcept;
type_safe::basic_variant::value_or
(1) template <typename T, typename U>
T value_or(variant_type<T> type, U&& other) const &;
(2) template <typename T, typename U>
T value_or(variant_type<T> type, U&& other) &&;
Returns: If the variant currently stores an object of type T
, returns a copy of that by copy (1)/move (2) constructing. Otherwise returns other
converted to T
.
Throws: Anything thrown by T
s copy (1)/move (2) constructor or the converting constructor.
Notes: T
must not necessarily be a type that can be stored in the variant.
Notes: This function does not participate in overload resolution, unless T
is copy (1)/move (2) constructible and the fallback convertible to T
.
type_safe::basic_variant::map
(1) template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::copy_constructible::value, Dummy>::type>
basic_variant map(Functor&& f, Args&&... args) const &;
(2) template <typename Functor, typename ... Args, typename Dummy = void, typename = typename std::enable_if<traits::move_constructible::value, Dummy>::type>
basic_variant map(Functor&& f, Args&&... args) &&;
Maps a variant with a function.
Effects: If the variant is not empty, calls the function using either std::forward<Functor>(f)(current-value, std::forward<Args>(args)...)
or member call syntax (current-value.*std::forward<Functor>(f))(std::forward<Args>(args)...)
. If those two expressions are both ill-formed, does nothing. \returns A new variant of the same type. It contains nothing, if *this
contains nothing. Otherwise, if the function was called, it contains the result of the function. Otherwise, it is a copy of the current variant. \throws Anything thrown by the function or copy/move constructor, in which case the variant will be left unchanged, unless the object was already moved into the function and modified there.
Requires: The result of the function - if it is called - can be stored in the variant.
Notes: (1) will use the copy constructor, (2) will use the move constructor. The function does not participate in overload resolution, if copy (1)/move (2) constructors are not available for all types.
type_safe::operator==
template <class VariantPolicy, typename Head, typename ... Types>
bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
Compares a ts::basic_variant with ts::nullvar.
A variant compares equal to nullvar
, when it does not have a value. A variant compares never less to nullvar
, nullvar
compares less only if the variant has a value. The other comparisons behave accordingly. \group variant_comp_null \module variant
type_safe::operator==
(1) template <class VariantPolicy, typename Head, typename ... Types>
bool operator==(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(2) template <class VariantPolicy, typename Head, typename ... Types>
bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
(3) template <class VariantPolicy, typename Head, typename ... Types>
bool operator!=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(4) template <class VariantPolicy, typename Head, typename ... Types>
bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
(5) template <class VariantPolicy, typename Head, typename ... Types>
bool operator<(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(6) template <class VariantPolicy, typename Head, typename ... Types>
bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
(7) template <class VariantPolicy, typename Head, typename ... Types>
bool operator<=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(8) template <class VariantPolicy, typename Head, typename ... Types>
bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
(9) template <class VariantPolicy, typename Head, typename ... Types>
bool operator>(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(10) template <class VariantPolicy, typename Head, typename ... Types>
bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, nullvar_t);
(11) template <class VariantPolicy, typename Head, typename ... Types>
bool operator>=(nullvar_t, const basic_variant<VariantPolicy, Head, Types...>& rhs);
type_safe::operator==
template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
Compares a ts::basic_variant with a value.
A variant compares equal to a value, if it contains an object of the same type and the object compares equal. A variant compares less to a value, if - when it has a different type - the type id compares less than the type id of the value, or - when it has the same type - the object compares less to the value. The other comparisons behave accordingly. \notes The value must not necessarily have a type that can be stored in the variant. \group variant_comp_t \module variant
type_safe::operator==
(1) template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator==(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(2) template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
(3) template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator!=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(4) template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
(5) template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator<(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(6) template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
(7) template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator<=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(8) template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
(9) template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator>(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(10) template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const T& rhs);
(11) template <class VariantPolicy, typename Head, typename ... Types, typename T>
bool operator>=(const T& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
type_safe::operator==
template <class VariantPolicy, typename Head, typename ... Types>
bool operator==(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
Compares two ts::basic_variants.
They compare equal if both store the same type (or none) and the stored object compares equal. A variant is less than another if they store mismatched types and the type id of the first is less than the other, or if they store the same type and the stored object compares less. The other comparisons behave accordingly. \module variant \group variant_comp
type_safe::operator!=
(1) template <class VariantPolicy, typename Head, typename ... Types>
bool operator!=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(2) template <class VariantPolicy, typename Head, typename ... Types>
bool operator<(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(3) template <class VariantPolicy, typename Head, typename ... Types>
bool operator<=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(4) template <class VariantPolicy, typename Head, typename ... Types>
bool operator>(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
(5) template <class VariantPolicy, typename Head, typename ... Types>
bool operator>=(const basic_variant<VariantPolicy, Head, Types...>& lhs, const basic_variant<VariantPolicy, Head, Types...>& rhs);
type_safe::with
[variant](1) template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
void with(basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);
(2) template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
void with(const basic_variant<VariantPolicy, Head, Types...>& variant, Func&& func, Args&&... additional_args);
(3) template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
void with(basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);
(4) template <class VariantPolicy, typename Head, typename ... Types, typename Func, typename ... Args>
void with(const basic_variant<VariantPolicy, Head, Types...>&& variant, Func&& func, Args&&... additional_args);
Effects: If the variant is empty, does nothing. Otherwise let the variant contain an object of type T
. If the functor is callable for the T
, calls its operator()
passing it the stored object. Else does nothing.
type_safe::fallback_variant_policy
[variant]template <typename Fallback>
class fallback_variant_policy
{
public:
using allow_empty = std::false_type;
template <typename T, typename ... Types, typename ... Args>
static void change_value(union_type<T> type, tagged_union<Types...>& storage, Args&&... args);
};
A variant policy for ts::basic_variant that uses a fallback type.
When changing the type of the variant throws an exception, the variant will create an object of the fallback type instead. The variant will never be empty.
Requires: Fallback
must be nothrow default constructible and a type that can be stored in the variant.
type_safe::fallback_variant
[variant]template <typename Fallback, typename ... OtherTypes>
using fallback_variant = basic_variant<fallback_variant_policy<Fallback>, Fallback, OtherTypes...>;
A ts::basic_variant using the ts::fallback_variant_policy.
This is a variant that is never empty, where exceptions on changing the type leaves it with a default-constructed object of the Fallback
type.
Requires: Fallback
must be nothrow default constructible.
type_safe::optional_variant_policy
[variant]class optional_variant_policy
{
public:
using allow_empty = std::true_type;
template <typename T, typename ... Types, typename ... Args>
static void change_value(union_type<T> type, tagged_union<Types...>& storage, Args&&... args);
};
A variant policy for ts::basic_variant that creates a variant with explicit empty state.
It allows an empty variant explicitly. When changing the type of the variant throws an exception, the variant will be left in that empty state.
type_safe::rarely_empty_variant_policy
[variant]using rarely_empty_variant_policy = 'hidden';
A variant policy for ts::basic_variant that creates a variant which is rarely empty.
When changing the type of the variant, it will use a the move constructor with a temporary. If the move constructor throws, the variant will be left in the empty state. Putting it into the empty state explicitly is not allowed.
type_safe::never_empty_variant_policy
[variant]using never_empty_variant_policy = 'hidden';
A variant policy for ts::basic_variant that creates a variant which is never empty.
Similar to ts::rarely_empty_variant_policy but when the move constructor throws, it calls std::terminate().
type_safe::variant
[variant]template <typename ... Types>
using variant = typename detail::select_variant_policy<Types...>::type;
A ts::basic_variant with the recommended default semantics.
If the first type is ts::nullvar_t it will use the ts::optional_variant_policy, which explicitly allows the empty state. Otherwise it will use the ts::rarely_empty_variant_policy where it tries to avoid the empty state as good as possible.
Notes: If you pass ts::nullvar_t as the first type, it is not actually one of the types that can be stored in the variant, but a tag to enable the empty state.